/*
 * @Author: Clark
 * @Email: haixuanwoTxh@gmail.com
 * @Date: 2023-01-28 17:15:36
 * @LastEditors: Clark
 * @LastEditTime: 2023-01-28 18:01:31
 * @Description: file content
 */
#include "apue.h"
#include <syslog.h>
#include <fcntl.h>
#include <sys/resource.h>

void daemonize(const char *cmd)
{
    int fd0, fd1, fd2;
    pid_t pid;
    struct rlimit rl;
    struct sigaction sa;

    // clear file creation mask
    umask(0);

    // get maximum number of file descriptors.
    if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
    {
        err_quit("%s: can't get file limit", cmd);
    }

    // Become a session leader to lose controlling TTY
    if ((pid = fork()) < 0)
    {
        err_quit("%s: can't fork", cmd);
    }
    else if (0 != pid)
    {
        exit(0);
    }

    setsid();

    // Ensure future opens won't allocate controlling TTYs
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGHUP, &sa, NULL) < 0)
    {
        err_quit("%s: can't ignore SIGHUP", cmd);
    }

    if ((pid = fork()) < 0)
    {
        err_quit("%s: can't fork", cmd);
    }
    else if (0 != pid)
    {
        exit(0);
    }

    // change the current working directory to the root so
    // we won't prevent file systems from being unmounted
    if (chdir("/") < 0)
    {
        err_quit("%s: can't change directory to /", cmd);
    }

    // close all open file descriptors
    if (RLIM_INFINITY == rl.rlim_max)
    {
        rl.rlim_max = 1024;
    }

    for (size_t i = 0; i < rl.rlim_max; i++)
    {
        close(i);
    }

    // Attach file descriptors 0, 1, 2 to /dev/null
    fd0 = open("/dev/null", O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);

    // Initialize the log file
    openlog(cmd, LOG_CONS, LOG_DAEMON);
    if (0 != fd0 || 1 != fd1 || 2 != fd2)
    {
        syslog(LOG_ERR, "unexpected file descriptors %d %d %d", fd0, fd1, fd2);
        exit(1);
    }
}
